﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StyleMVVM.DependencyInjection;
using StyleMVVM.Logging;
using StyleMVVM.Utilities;
using StyleMVVM.ViewModel;
using StyleMVVM.Data;
#if !DOT_NET
using Windows.Foundation;
using Windows.Foundation.Metadata;
#endif
#if NETFX_CORE
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

#else
using System.Windows;
using System.Windows.Controls;

#endif

namespace StyleMVVM.View.Regions.Adapters
{
	public sealed class FrameAdapter : IRegionAdapter, IDependencyInjectionContainerAware
	{
		private static string supplemental = typeof(FrameAdapter).FullName;
		private IViewBinderService viewBinder;

		public static void RegisterExport(IDependencyInjectionContainer container)
		{
			container.Register(typeof(FrameAdapter)).
			          As(typeof(IRegionAdapter));
		}

		public Type AddapterType
		{
			get { return typeof(Frame); }
		}

		public IEnumerable<object> GetCurrentExports(IRegion region, object control)
		{
			List<object> returnValue = new List<object>();
			object content = ((Frame)control).Content;

			if (content != null)
			{
				returnValue.Add(content);
			}

			return returnValue;
		}

#if NETFX_CORE
		public IAsyncOperation<bool> Activate(IRegion region, object control, string newExport)
		{
			throw new NotImplementedException();
		}

		public IAsyncOperation<bool> Deactivate(IRegion region, object control, string newExport)
		{
			throw new NotImplementedException();
		}

		public IAsyncOperation<bool> Navigate(IRegion region, object control, string newExport, object navigationParameter)
		{
			throw new NotImplementedException();
		}

		[DefaultOverload]
		public IAsyncOperation<bool> Add(IRegion region, object control, string newExportName, object navigationParameter)
		{
			throw new NotImplementedException();
		}

		public IAsyncOperation<bool> Add(IRegion region, object control, object newExport, object navigationParameter)
		{
			throw new NotImplementedException();
		}

		[DefaultOverload]
		public IAsyncOperation<bool> Remove(IRegion region, object control, string oldExportName)
		{
			throw new NotImplementedException();
		}

		public IAsyncOperation<bool> Remove(IRegion region, object control, object oldExport)
		{
			throw new NotImplementedException();
		}
#else
		public Task<bool> Activate(IRegion region, object control, string newExport)
		{
			throw new NotImplementedException();
		}

		public Task<bool> Deactivate(IRegion region, object control, string newExport)
		{
			throw new NotImplementedException();
		}

		public Task<bool> Navigate(IRegion region, object control, string newExport, object navigationParameter)
		{
			throw new NotImplementedException();
		}

		[DefaultOverload]
		public Task<bool> Add(IRegion region, object control, string newExportName, object navigationParameter)
		{
			throw new NotImplementedException();
		}

		public Task<bool> Add(IRegion region, object control, object newExport, object navigationParameter)
		{
			throw new NotImplementedException();
		}

		[DefaultOverload]
		public Task<bool> Remove(IRegion region, object control, string oldExportName)
		{
			throw new NotImplementedException();
		}

		public Task<bool> Remove(IRegion region, object control, object oldExport)
		{
			throw new NotImplementedException();
		}
#endif

		private IViewBinderService ViewBinder
		{
			get
			{
				if (viewBinder == null)
				{
					viewBinder = Container.LocateByType(typeof(IViewBinderService)) as IViewBinderService;
				}

				return viewBinder;
			}
		}

		private IEnumerable<TExport> GetCurrentExports<TExport>(IRegion region, Frame control)
		{
			List<TExport> returnValue = new List<TExport>();
			IList addList = returnValue;

			if (control.Content != null)
			{
				addList.Add(control.Content);
			}

			return returnValue;
		}

		private Task<bool> Navigate(IRegion region, Frame contorl, string newExport, object navigationParameter = null)
		{
			return Add(region, contorl, newExport, navigationParameter);
		}

		private Task<bool> Add(IRegion region, Frame control, string newExportName, object navigationParameter = null)
		{
			Type newExport = Container.LocateExportType(newExportName);

			if (newExport != null)
			{
#if WINDOWS_PHONE
				Logging.Logger.Error("Frame navigation using regions is not yet supported");
#else
				control.Navigate(newExport, navigationParameter);
#endif

				ViewBinder.Bind(newExport, navigationParameter);
			}

			return InternalTaskHelper.ReturnTask(true);
		}

		private Task<bool> Remove(IRegion region, Frame control, string oldExportName)
		{
			if (control.Content != null)
			{
				control.Content = null;

				return InternalTaskHelper.ReturnTask(true);
			}

			return InternalTaskHelper.ReturnTask(false);
		}

		private async Task<bool> Add(IRegion region, Frame control, object newExport, object navigationParameter = null)
		{
			throw new Exception("Adding to a d frame by object is not supported in Winrt");
		}

		private Task<bool> Remove(IRegion region, Frame control, object oldExport)
		{
			if (control.Content != null)
			{
				control.Content = null;

				return InternalTaskHelper.ReturnTask(true);
			}

			return InternalTaskHelper.ReturnTask(false);
		}

		private Task<bool> Activate(IRegion region, Frame control, string newExport)
		{
			if (control.Content is UIElement)
			{
				((UIElement)control.Content).Visibility = Visibility.Visible;

				return InternalTaskHelper.ReturnTask(true);
			}

			return InternalTaskHelper.ReturnTask(false);
		}

		private Task<bool> Deactivate(IRegion region, Frame control, string newExport)
		{
			if (control.Content is UIElement)
			{
				((UIElement)control.Content).Visibility = Visibility.Collapsed;

				return InternalTaskHelper.ReturnTask(true);
			}

			return InternalTaskHelper.ReturnTask(false);
		}

		private async Task<bool> CallNavigatingFrom(IRegion region, FrameworkElement oldExport)
		{
			if (oldExport != null && oldExport.DataContext is INavigationViewModel)
			{
				INavigationViewModel navigationViewModel = oldExport.DataContext as INavigationViewModel;

				StyleNavigatingCancelEventArgs args = new StyleNavigatingCancelEventArgs();

				await navigationViewModel.NavigatingFrom(oldExport, args);

				return args.Cancel;
			}

			return false;
		}

		private void CallNavigatedTo(IRegion region, FrameworkElement newExport, object navigationParameter)
		{
			if (newExport != null)
			{
				IRegionAware regionAware = newExport.DataContext as IRegionAware;

				if (regionAware != null)
				{
					regionAware.Region = region;
				}

				if (newExport.DataContext is INavigationViewModel)
				{
					INavigationViewModel navigationViewModel = newExport.DataContext as INavigationViewModel;

					navigationViewModel.NavigationParameter = navigationParameter;

					navigationViewModel.NavigatedTo(newExport, new StyleNavigationEventArgs());
				}
			}
		}

		private void CallNavigatedFrom(IRegion region, FrameworkElement oldExport)
		{
			if (oldExport != null)
			{
				IRegionAware regionAware = oldExport.DataContext as IRegionAware;

				if (regionAware != null)
				{
					regionAware.Region = region;
				}

				INavigationViewModel navigationViewModel = oldExport.DataContext as INavigationViewModel;

				if (navigationViewModel != null)
				{
					navigationViewModel.NavigatedFrom(oldExport, null);
				}
			}
		}

		public IDependencyInjectionContainer Container { get; set; }
	}
}